#pragma once
#include <functional>
#pragma once
#include<functional>



namespace zj
{
	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr = nullptr)
			: _ptr(ptr)
			, pcount(new int(1))
		{}

		template<class D>
		shared_ptr(T* ptr, D del)
			: _ptr(ptr)
			, pcount(new int(1))
			,_del(del)
		{}

		// sp2(sp1)
		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			,pcount(sp.pcount)
		{
			++(*pcount);
		}

		void release()
		{
			if ((*pcount) == 1)
			{
				//delete _ptr;
				_del(_ptr);

				delete pcount;
				_ptr = nullptr;
				pcount = nullptr;
                return ;
			}
            (*pcount)--;
		}

		// sp1 = sp3
		// sp3 = sp3
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				release();

				_ptr = sp._ptr;
				pcount = sp.pcount;
				++(*pcount);
			}

			return *this;
		}

		~shared_ptr()
		{
			release();
		}

		T* get() const
		{
			return _ptr;
		}

		int use_count() const
		{
			return *pcount;
		}

		T& operator*()
		{ 
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
		int* pcount;

		std::function<void(T* ptr)> _del = [](T* ptr) {delete ptr; };
	};
}
